package com.oweight.com2tpc.connect.serial;

import com.oweight.com2tpc.Controller;
import com.oweight.com2tpc.connect.serial.jserialcomm.JSerialCommChannel;
import com.oweight.com2tpc.connect.serial.jserialcomm.JSerialCommChannelOption;
import com.oweight.com2tpc.connect.serial.jserialcomm.JSerialCommDeviceAddress;
import com.oweight.com2tpc.connect.serial.jserialcomm.JSerialCommChannelConfig;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Executors;

/**
 * @author Rubin
 * @version v1 2020/6/26 9:43
 */
@Slf4j
public class SerialClient {

    public static Channel channel;

    private static boolean reconnection = false;

    public static void start(Controller controller) {

        EventLoopGroup group = new OioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(JSerialCommChannel.class)
                    .option(JSerialCommChannelOption.READ_TIMEOUT, 1000)
                    .option(JSerialCommChannelOption.BAUD_RATE, Integer.parseInt(Controller.baudRateStr))
                    .option(JSerialCommChannelOption.DATA_BITS, 8)
                    .option(JSerialCommChannelOption.PARITY_BIT, JSerialCommChannelConfig.Paritybit.NO_PARITY)
                    .option(JSerialCommChannelOption.STOP_BITS, JSerialCommChannelConfig.Stopbits.ONE_STOP_BIT)
                    .handler(new ChannelInitializer<JSerialCommChannel>() {
                        @Override
                        public void initChannel(JSerialCommChannel ch) throws Exception {
                            ch.pipeline().addLast(
                                    new ByteArrayEncoder(),
                                    new ByteArrayDecoder(),
                                    new SerialDataHandler(controller));
                        }
                    });

            ChannelFuture f = b.connect(new JSerialCommDeviceAddress(Controller.serialPortStr)).sync();
            if (f.isSuccess()) {
                log.info("Open port: " + Controller.serialPortStr);
                log.info("Connected success.");
                Controller.connectionSucceeded(controller.comStatus, controller.comConnect);
                reconnection = false;
            }
            channel = f.channel();
            channel.closeFuture().sync();

        } catch (Exception e) {
            log.info("Connected failed!", e);
        } finally {
            log.info("Closing");
            group.shutdownGracefully();
            Controller.connectionFailed(controller.comStatus, null);
            // 自动连接
            Executors.newSingleThreadExecutor().execute(() -> {
                do {
                    if (Controller.comInitiativeDisconnect) {
                        // 用户自行断开连接
                        break;
                    }

                    log.info("自动重连...");
                    try {
                        SerialClient.start(controller);
                    } catch (Exception e) {
                        log.error("串口断开连接！");
                    }
                } while (reconnection);
            });
        }
    }

    public static void stop() {
        if (channel != null) {
            channel.close();
        }
    }
}
